<?php

namespace App\Console\Commands;


use Aitels\Foundation\Code\ClassBuilder;
use Aitels\Foundation\Generate\ClassFileGenerator;
use Illuminate\Console\Command;
use Illuminate\Support\Str;

class GenerateController extends Command
{
    protected $signature = 'gen:controller';
    protected $description = '根据模型自动生成curd 控制器、路由';

    public function handle()
    {
        app()->genCommand = $this;
        $list = [
            'admin' => [
//                'task' => 'r,rid,config-rate,audit',
//                'enterprise' => 'retrieve-credit-score,minus-credit-score',
//                'employee' => 'retrieve-credit-score,minus-credit-score',
//                'enterprise-rate' => 'r',
//                'employee-rate' => 'r',
//                'enterprise-complaint' => 'r,rid,edit-outcome',
//                'employee-complaint' => 'r,rid,edit-outcome',
//                'rate-tag' => 'r,c,u,disable'
//            'trash'=>'r,recover'
                'CommissionDepartment' =>'r,u,c,disable',
                'Commissioner'=>'r,u,c,disable',
                'CommissionerEnterprise' =>'c',
                'CommissionerIgnore' =>'c,r',
                'CommissionerRecord' =>'r,calculate'
            ],
            'web' => [
//                'task' => 'c,r,rid,qr-code',
//                'task-employee' => 'r,rid,accept,deny',
//                'task-check-apply' => 'r,deny,create-trade',
//                'employee-rate' => 'c,r',
//                'employee-complaint' => 'c,r',
//                'rate-tag' => 'r'
            ],
            'wechat' => [
//                'task' => 'r,rid,enroll,my',
//                'task-check-apply' => 'c,r,u',
//                'enterprise-rate' => 'c,r',
//                'enterprise-complaint' => 'c,r',
//                'rate-tag' => 'r'
            ]
        ];


        $generator = new ClassFileGenerator();
        $definitions = [];
        foreach ($list as $module => $arr) {
            foreach ($arr as $modelName => $commands) {
                $modelName = Str::studly($modelName);
                $commands = explode(',', $commands);
                $path = "\\Modules\\".ucfirst($module)."\\Http\\Controllers\\$modelName\\";
                if (in_array('c', $commands)) {
                    $definitions[$path.'Create'] = $this->createControllerDefinition($module, $modelName);
                }
                if (in_array('u', $commands)) {
                    $definitions[$path.'Update'] = $this->updateControllerDefinition($module, $modelName);
                }
                if (in_array('r', $commands)) {
                    if (in_array('rid', $commands)) {
                        $definitions[$path.'Retrieve'] = $this->retrieveControllerDefinition($module, $modelName, true);
                    } else {
                        $definitions[$path.'Retrieve'] = $this->retrieveControllerDefinition($module, $modelName,
                            false);
                    }
                }
                collect($commands)->filter(function ($command) {
                    return !in_array($command, ['c', 'u', 'r', 'rid']);
                })->each(function ($command) use ($path, $module, $modelName, &$definitions) {
                    $definitions[$path.Str::studly($command)] = $this->otherControllerDefinition($module, $modelName,
                        $command);
                });
            }
        }

        $generator->generateByDefinitions($definitions);
    }

    protected function createControllerDefinition($module, $modelName)
    {
        $columns = $this->getColumns($modelName);
        $partitionColumns = collect($columns)
            ->filter(function ($column) {
                return !in_array($column, ['created_at', 'updated_at', 'deleted_at']);
            })
            ->partition(function ($column) {
                return !Str::contains($column, ['id', 'status', 'type', 'code', 'at']);
            })->all();
        $unsafeColumns = implode("' , '", $partitionColumns[0]->all());
        $safeColumns = $partitionColumns[1]->all();
        unset($safeColumns[array_search('id', $safeColumns)]);
        $safeColumns = implode("'=>'' , '", $safeColumns);

        if ($safeColumns) {
            $code = <<<CODE
$modelName::safeCreateWithRequestParams(
        ['%s'],
        ['%s'=>'']
        );
        return Api::success();
CODE;
        } else {
            $code = <<<CODE
$modelName::safeCreateWithRequestParams(
        ['%s']
        );
        return Api::success();
CODE;
        }


        $code = sprintf($code, $unsafeColumns, $safeColumns);

        return [
            'methods' => [
                'index' => [
                    'code' => $code,
                    'modifier' => ClassBuilder::PUBLIC,
                    'comments' => [
                        "@Route(path=/api/$module/".Str::kebab($modelName).'  method=post)',
                    ],
                ],
            ],
            'uses' => [
                'Modules\\Common\\Models\\'.$modelName,
                'Modules\Common\Util\Api'
            ],
        ];
    }

    protected function updateControllerDefinition($module, $modelName)
    {
        $columns = $this->getColumns($modelName);
        $partitionColumns = collect($columns)
            ->filter(function ($column) {
                return !in_array($column, ['created_at', 'updated_at', 'deleted_at']);
            })
            ->partition(function ($column) {
                return !Str::contains($column, ['id', 'status', 'type', 'code', 'at']);
            })->all();
        $unsafeColumns = implode("' , '", $partitionColumns[0]->all());


        $code = <<<CODE
$modelName::safeUpdateWithRequestParams(['%s']);
        return Api::success();
CODE;
        $code = sprintf($code, $unsafeColumns);

        return [
            'methods' => [
                'index' => [
                    'code' => $code,
                    'modifier' => ClassBuilder::PUBLIC,
                    'comments' => [
                        "@Route(path=/api/$module/".Str::kebab($modelName).'  method=put)',
                    ],

                ],
            ],
            'uses' => [
                'Modules\\Common\\Models\\'.$modelName,
                'Modules\Common\Util\Api'
            ],
        ];
    }

    protected function retrieveControllerDefinition($module, $modelName, $retrieveById)
    {
        $columns = $this->getColumns($modelName);
        $columns = collect($columns)->filter(function ($column) {
            return !in_array($column, ['updated_at', 'deleted_at']);
        })->all();
        $columns = implode("' , '", $columns);
        $retrieveCode = <<<'CODE'
$data = %s::latest()
        ->select(['%s'])
        ->paginate(request('per_page', 15));
        return Api::success($data);
CODE;
        $retrieveCode = sprintf($retrieveCode, $modelName, $columns);

        $retrieveByIdCode = <<<'CODE'
$data = %s::find($id, ['%s']);
        return Api::success($data);
CODE;
        $retrieveByIdCode = sprintf($retrieveByIdCode, $modelName, $columns);
        if ($retrieveById) {
            return [
                'methods' => [
                    'retrieve' => [
                        'code' => $retrieveCode,
                        'modifier' => ClassBuilder::PUBLIC,
                        'comments' => [
                            "@Route(path=/api/$module/".Str::kebab($modelName).')',
                        ],

                    ],
                    'retrieveOne' => [
                        'code' => $retrieveByIdCode,
                        'modifier' => ClassBuilder::PUBLIC,
                        'comments' => [
                            "@Route(path=/api/$module/".Str::kebab($modelName).'/{id})',
                        ],
                        'params' => 'int $id'
                    ],
                ],
                'uses' => [
                    'Modules\\Common\\Models\\'.$modelName,
                    'Modules\Common\Util\Api'
                ],
            ];
        } else {
            return [
                'methods' => [
                    'retrieve' => [
                        'code' => $retrieveCode,
                        'modifier' => ClassBuilder::PUBLIC,
                        'comments' => [
                            "@Route(path=/api/$module/".Str::kebab($modelName).')',
                        ],

                    ],
                ],
                'uses' => [
                    'Modules\\Common\\Models\\'.$modelName,
                    'Modules\Common\Util\Api',

                ],
            ];
        }

    }


    protected function otherControllerDefinition($module, $modelName, $action)
    {
        $code = <<<CODE
CODE;

        return [
            'methods' => [
                'index' => [
                    'code' => $code,
                    'modifier' => ClassBuilder::PUBLIC,
                    'comments' => [
                        "@Route(path=/api/$module/".Str::kebab($modelName).'/'.$action.'  method=put)',
                    ],

                ],
            ],
            'uses' => [
                'Modules\\Common\\Models\\'.$modelName,
                'Modules\Common\Util\Api'
            ],
        ];
    }


    protected function getColumns($modelName)
    {
        $databaseDefinitions = require storage_path('design/cache.php');
        foreach ($databaseDefinitions as $table) {
            if ($table['tableModelName'] === $modelName) {
                return array_column($table['columns'], 'name');
            }
        }
    }

}
